import groovy.net.xmlrpc.*

/*
 * This class decides what method to call based on the Xml RPC request.
 * It checks to see if the class actually has the method.
 * If it does it calls it.
 * Otherwise, it checks to see if the method name is mapped
 * to a new name.
 * If there is a method with the new name, then that method is called.
 * This is uses some code from John Wilson;s XMLRPCServer
 */

class Xmlrpc {

    // XML header
    static final String xmlDeclaration = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"

    // Service the XML RPC request
    // Returns the value from the actual method call
    // Returns null, on error.
    def service(request, response) {
        // get the InputStream
        def inStream = request.inputStream

        // process the input with the  XML RPC message processor
        def requestParser = new XMLRPCMessageProcessor()
        requestParser.parseMessage(inStream)

        def methodName = requestParser.getMethodname()
        def params = requestParser.getParams()

        def method
        def field
        def result

        // check to see if this class has a method called methodName
        try {
            method = this.class.getMethod( methodName, [ Object ] as Class[] )

        } catch (NoSuchMethodException nsme1) {
            // didnt find that method by name
            // so we look it up in the mappings

            def mapping

            try {
                mapping = this.getProperty('mapping')
            } catch (MissingPropertyException mpe) {
                def message =  "No method for service: " + methodName
                error(0, message, response)
                return null

            }

            def newName = mapping[methodName]

            if (newName) {
                // got a new name, so try and find the method
                try {
                    method = this.class.getMethod( newName, [ Object ] as Class[] )
                } catch (NoSuchMethodException nsmee2) {
                    // didnt find by new name
                    def message =  "No method for service: " + newName
                    error(0, message, response)
                    return null
                }

            } else {
                def message =  "No method for service: " + methodName
                error(0, message, response)
                return null

            }

        }

        // call the method
        try {
            result = method.invoke(this, params)

            success(result, response)

            return result

        } catch (Exception e) {
            error(0, e.message, response)
            return null
        }

    }

    // render a successful response
    private success(obj, response) {
        def answer = XMLRPCMessageProcessor.emitResult(new StringBuffer(xmlDeclaration), obj).toString().getBytes("ISO-8859-1");

        response.contentLength = answer.length
        response.outputStream.write(answer)
    }

    // render an error response
    private error(codeValue, obj, response) {
        def answer = XMLRPCMessageProcessor.emitError(new StringBuffer(xmlDeclaration), codeValue, obj).toString().getBytes("ISO-8859-1")
               
        response.contentLength = answer.length
        response.outputStream.write(answer)
    }
}
